package com.person.jiaiplan.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.person.jiaiplan.assembler.AchievementLogsAssembler;
import com.person.jiaiplan.assembler.ScheduleSettingAssembler;
import com.person.jiaiplan.pojo.dto.AchievementShowVo;
import com.person.jiaiplan.pojo.dto.PlanInfoReqDTO;
import com.person.jiaiplan.pojo.dto.PlanInfoResDTO;
import com.person.jiaiplan.pojo.dto.SchedulePlanShowVO;
import com.person.jiaiplan.pojo.dto.calendar.CalendarQueryResDTO;
import com.person.jiaiplan.pojo.dto.calendar.CalendarWorkCard;
import com.person.jiaiplan.pojo.entity.AchievementLogs;
import com.person.jiaiplan.pojo.entity.Clocklogs;
import com.person.jiaiplan.pojo.entity.ScheduleLogs;
import com.person.jiaiplan.pojo.entity.SchedulePlanLogs;
import com.person.jiaiplan.service.*;
import com.person.jiaiplan.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ScheduleCommonQueryServiceImpl implements ScheduleCommonQueryService {

    @Autowired
    private ScheduleLogsService scheduleLogsService;

    @Autowired
    private SchedulePlanLogsService schedulePlanLogsService;

    @Autowired
    private ClocklogsService clocklogsService;

    @Autowired
    private AchievementLogsService achievementLogsService;

    @Override
    public IPage<PlanInfoResDTO> queryPlanInfo(PlanInfoReqDTO reqDTO) {

        // 如果没有传入时间，就默认查询本月的
        if (StrUtil.isBlank(reqDTO.getStartTime()) || StrUtil.isBlank(reqDTO.getEndTime())) {
            reqDTO.setStartTime(DateUtil.format(DateUtil.beginOfMonth(DateUtil.date()), "yyyy-MM-dd"));
            reqDTO.setEndTime(DateUtil.format(DateUtil.endOfMonth(DateUtil.date()), "yyyy-MM-dd"));
        }

        // 创建分页对象
        IPage<ScheduleLogs> page = new Page<>(reqDTO.getPageNum(), reqDTO.getPageSize());
        QueryWrapper<ScheduleLogs> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("operator_type", Integer.valueOf(reqDTO.getOperatorType()));
        queryWrapper.eq("plan_status", Integer.valueOf(reqDTO.getPlanStatus()));
        if (reqDTO.getModel() != "" && reqDTO.getModel() != null) {
            queryWrapper.eq("model", reqDTO.getModel());
        }
        if (reqDTO.getContent() != "" && reqDTO.getContent() != null) {
            queryWrapper.like("content", reqDTO.getContent());
        }
//        if (reqDTO.getStartTime() != "" && reqDTO.getStartTime() != null) {
//            queryWrapper.between("create_time", DateUtil.beginOfDay(DateUtil.parse(reqDTO.getStartTime())), DateUtil.endOfDay(DateUtil.parse(reqDTO.getEndTime())));
//        }

        page = scheduleLogsService.getBaseMapper().selectPage(page, queryWrapper);
        List<PlanInfoResDTO> planInfoResDTOList = ScheduleSettingAssembler.INSTANCE.toPlanInfoResDTOList(page.getRecords());
        // 插入周期明细数据
        planInfoResDTOList = queryCycleList(planInfoResDTOList);
        // 根据周期配置筛选数据
        planInfoResDTOList = checkPlanCycle(planInfoResDTOList, reqDTO.getStartTime(), reqDTO.getEndTime());
        CollectionUtil.sort(planInfoResDTOList, new Comparator<PlanInfoResDTO>() {
            @Override
            public int compare(PlanInfoResDTO o1, PlanInfoResDTO o2) {

                // 今日打卡情况是需打卡的排在最前面
                if (o1.getTodayCheckIn() != null && o1.getTodayCheckIn() == 2) {
                    return -1;
                }

                if (o1.getPlanShowVO() != null && o1.getPlanShowVO().getNextTime() != null) {
                    if (o2.getPlanShowVO() != null && o2.getPlanShowVO().getNextTime() != null) {
                        return o1.getPlanShowVO().getNextTime().compareTo(o2.getPlanShowVO().getNextTime());
                    }
                }

                // 按照模块名称排序
                if (o1.getModel() != null && o2.getModel() != null) {
                    return o1.getModel().compareTo(o2.getModel());
                }

                return 1;
            }
        });

        IPage<PlanInfoResDTO> planInfoResDTOIPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        planInfoResDTOIPage.setRecords(planInfoResDTOList);
        return planInfoResDTOIPage;
    }

    @Override
    public CalendarQueryResDTO queryCalendarByDay(String dateTime) {
        // 查询周期配置，开始时间和结束时间包含这个时间的
        List<SchedulePlanLogs> schedulePlanLogsList = schedulePlanLogsService.getBaseMapper().selectList(Wrappers.lambdaQuery(SchedulePlanLogs.class)
                .le(SchedulePlanLogs::getPlanStartTime, DateUtil.endOfDay(DateUtil.parse(dateTime)))
                .ge(SchedulePlanLogs::getPlanFinishTime, DateUtil.beginOfDay(DateUtil.parse(dateTime))));

        List<Long> scheduleIds = new ArrayList<>();
        // 周期配置的打卡时间列表包含这个时间
        List<SchedulePlanLogs> planLogsList = schedulePlanLogsList.stream().filter(vo -> vo.getPlanLockTime().contains(dateTime)).collect(Collectors.toList());
        scheduleIds.addAll(planLogsList.stream().map(SchedulePlanLogs::getScheduleId).map(Long::valueOf).collect(Collectors.toList()));
        // 查询今天打卡的记录
        List<Clocklogs> clocklogsList = clocklogsService.getBaseMapper().selectList(
                Wrappers.lambdaQuery(Clocklogs.class)
                        .eq(Clocklogs::getClockTime, DateUtil.parse(dateTime))
                        .eq(Clocklogs::getClockType, 1));

        scheduleIds.addAll(clocklogsList.stream().map(Clocklogs::getScheduleId).collect(Collectors.toList()));
        if (scheduleIds.size() == 0) {
            return new CalendarQueryResDTO();
        }
        // 根据 scheduleID 找到 logs
        List<ScheduleLogs> scheduleLogsList = scheduleLogsService.getBaseMapper().selectList(
                Wrappers.lambdaQuery(ScheduleLogs.class)
                        .in(ScheduleLogs::getId, scheduleIds));
        return createCalendarQueryResDTO(planLogsList, clocklogsList, scheduleLogsList);
    }

    /**
     * 创建日历展示对象
     *
     * @param planLogsList
     * @param clocklogsList
     * @param scheduleLogsList
     * @return
     */
    private CalendarQueryResDTO createCalendarQueryResDTO(List<SchedulePlanLogs> planLogsList, List<Clocklogs> clocklogsList, List<ScheduleLogs> scheduleLogsList) {
        CalendarQueryResDTO calendarQueryResDTO = new CalendarQueryResDTO();
        List<SchedulePlanLogs> finishPlanInfo = new ArrayList<>();
        CalendarWorkCard finishCard = configCalendarCard();
        clocklogsList.stream().forEach(vo -> {

            List<SchedulePlanLogs> schedulePlanLogs = planLogsList.stream().filter(plan -> plan.getScheduleId().equals(String.valueOf(vo.getScheduleId()))).collect(Collectors.toList());
            // 如果是已打卡的，有计划的，则将计划对象删除
            if (schedulePlanLogs != null || schedulePlanLogs.size() >= 0) {
                finishPlanInfo.addAll(schedulePlanLogs);
            }
            // 找到打卡对象的类型
            ScheduleLogs scheduleLogs = scheduleLogsList.stream().filter(logs -> logs.getId().equals(vo.getScheduleId())).findFirst().get();
            Integer operatorType = scheduleLogs.getOperatorType();
            if (operatorType.equals(1)) {
                finishCard.getWorkCard().add(createCardContent(scheduleLogs));
            } else if (operatorType.equals(3)) {
                finishCard.getLearnCard().add(createCardContent(scheduleLogs));

            } else if (operatorType.equals(2)) {
                finishCard.getLifeCard().add(createCardContent(scheduleLogs));
            }

        });
        calendarQueryResDTO.setFinish(finishCard);
        // 去除已打卡的计划
        planLogsList.removeAll(finishPlanInfo);


        CalendarWorkCard unFinishCard = configCalendarCard();

        planLogsList.stream().forEach(vo -> {
            ScheduleLogs scheduleLogs = scheduleLogsList.stream().filter(logs -> logs.getId().equals(Long.valueOf(vo.getScheduleId()))).findFirst().get();
            Integer operatorType = scheduleLogs.getOperatorType();
            // 如果是已完成的计划 ，则不展示
            if (2 == scheduleLogs.getPlanStatus()) {
                return;
            }
            if (operatorType.equals(1)) {
                unFinishCard.getWorkCard().add(createCardContent(scheduleLogs));
            } else if (operatorType.equals(3)) {
                unFinishCard.getLearnCard().add(createCardContent(scheduleLogs));

            } else if (operatorType.equals(2)) {
                unFinishCard.getLifeCard().add(createCardContent(scheduleLogs));
            }
        });
        calendarQueryResDTO.setUnFinish(unFinishCard);
        return calendarQueryResDTO;
    }


    /**
     * 创建卡片内容
     *
     * @param scheduleLogs
     * @return
     */
    private String createCardContent(ScheduleLogs scheduleLogs) {
        String content = scheduleLogs.getModel() + "-" + scheduleLogs.getContent();
        if (StrUtil.isNotBlank(scheduleLogs.getContentDetail())) {
            content += "-" + scheduleLogs.getContentDetail();
        }
        return content;
    }


    /**
     * 初始化卡片信息
     *
     * @return
     */
    private CalendarWorkCard configCalendarCard() {
        CalendarWorkCard card = new CalendarWorkCard();
        card.setWorkCard(new ArrayList<>());
        card.setLearnCard(new ArrayList<>());
        card.setLifeCard(new ArrayList<>());
        return card;
    }


    /**
     * 检查周期配置筛选
     *
     * @param planInfoResDTOList
     * @return
     */
    private List<PlanInfoResDTO> checkPlanCycle(List<PlanInfoResDTO> planInfoResDTOList, String queryStartTime, String queryEndTime) {
        List<PlanInfoResDTO> addList = new LinkedList<>();

        // 根据周期去筛选数据 , 没有周期的数据不需要去查询打卡数据 ，也不展示在周计划中
        planInfoResDTOList.stream().forEach(vo -> {
                    String scheduleId = vo.getId();
                    SchedulePlanLogs schedulePlanLogs = schedulePlanLogsService.getOne(Wrappers.lambdaQuery(SchedulePlanLogs.class).eq(SchedulePlanLogs::getScheduleId, scheduleId));
                    if (schedulePlanLogs != null) {
                        Date planStartTime = schedulePlanLogs.getPlanStartTime();
                        Date planEndTime = schedulePlanLogs.getPlanFinishTime();
                        Date startTime = DateUtil.beginOfDay(DateUtil.parse(queryStartTime));
                        Date endTime = DateUtil.endOfDay(DateUtil.parse(queryEndTime));

                        // 计划开始时间 < 查询结束
                        if (planStartTime.getTime() < endTime.getTime()) {
                            // 计划结束时间 > 查询开始
                            if (planEndTime.getTime() > startTime.getTime()) {
                                addList.add(vo);
                            }
                        }
                    } else {
                        // 没有周期的数据，则根据 startTime 和 endTime 进行筛选 ,处理未进行周期配置的或者是补卡的数据
                        Date startTime = DateUtil.beginOfDay(DateUtil.parse(queryStartTime));
                        Date endTime = DateUtil.endOfDay(DateUtil.parse(queryEndTime));
                        Date createTime = vo.getCreateTime();
                        if (createTime.getTime() >= startTime.getTime() && createTime.getTime() <= endTime.getTime()) {
                            addList.add(vo);
                        }

                    }
                }

        );
        return addList;
    }

    /**
     * 查询周期明细/打卡明细
     *
     * @param planInfoResDTOList
     * @return
     */
    private List<PlanInfoResDTO> queryCycleList(List<PlanInfoResDTO> planInfoResDTOList) {
        for (PlanInfoResDTO planInfoResDTO : planInfoResDTOList) {
            SchedulePlanShowVO showVO = new SchedulePlanShowVO();
            Long scheduleId = Long.valueOf(planInfoResDTO.getId());
            SchedulePlanLogs schedulePlanLogs = schedulePlanLogsService.getOne(Wrappers.lambdaQuery(SchedulePlanLogs.class).eq(SchedulePlanLogs::getScheduleId, scheduleId));
            Integer planCounts = 0;
            Integer planExecutionsCount = 0;
            String[] timeList = null;
            List<String> timeLists = new ArrayList<>();
            if (schedulePlanLogs != null) {
                timeList = schedulePlanLogs.getPlanLockTime().substring(1, schedulePlanLogs.getPlanLockTime().length() - 1).replaceAll(" ", "").split(",");
                showVO.setNextTime(DateUtils.getNextTime(timeList));
                showVO.setSumCount(schedulePlanLogs.getPlanCounts());
                showVO.setTimeList(schedulePlanLogs.getPlanLockTime());
                planCounts = schedulePlanLogs.getPlanCounts();
                timeLists = Arrays.asList(timeList);
                // 根据sheduleId 查询所有的打卡记录
                List<Clocklogs> clocklogs = clocklogsService.list(Wrappers.lambdaQuery(Clocklogs.class).eq(Clocklogs::getScheduleId, scheduleId));
                if (clocklogs != null && clocklogs.size() > 0) {
                    showVO.setFinishCount(clocklogs.size());
                    showVO.setUnfinishCount(showVO.getSumCount() - showVO.getFinishCount());
                    // 已打卡时间列表
                    List clockList = new LinkedList();
                    for (int i = 0; i < clocklogs.size(); i++) {
                        String clockTime = DateUtil.format(clocklogs.get(i).getClockTime(), "yyyy-MM-dd");
                        clockList.add(clockTime);
                        if (planCounts >= 0) {
                            // 执行时间包含了打卡时间
                            if (CollectionUtil.contains(timeLists, clockTime)) {
                                planExecutionsCount++;
                                planCounts--;
                            }
                        }
                    }

                    showVO.setClockInTimeList(Arrays.toString(clockList.toArray()));
                    showVO.setPlanExecutionsCount(planExecutionsCount);
                    showVO.setPlanUnexecutedCount(planCounts);
                }

                // 处理今日打卡情况
                Boolean todayCheckIn = false;
                if (clocklogs != null && clocklogs.stream().anyMatch(clocklog -> DateUtil.format(clocklog.getClockTime(), "yyyy-MM-dd").equals(DateUtil.format(new Date(), "yyyy-MM-dd")))) {
                    todayCheckIn = true;
                }
                planInfoResDTO.setTodayCheckIn(getTodayCheckIn(timeLists, todayCheckIn));

            }
            planInfoResDTO.setPlanShowVO(showVO);
            List<AchievementLogs> achievementLogsList = achievementLogsService.list(Wrappers.<AchievementLogs>lambdaQuery().eq(AchievementLogs::getScheduleId, scheduleId));
            if (achievementLogsList != null && achievementLogsList.size() > 0) {
                List<AchievementShowVo> achievementShowVoList = AchievementLogsAssembler.INSTANCE.toAchievementShowVoList(achievementLogsList);
                planInfoResDTO.setAchievementShowVoList(achievementShowVoList);
            }

        }

        // 按照今日打卡情况排序
        CollectionUtil.sort(planInfoResDTOList, Comparator.nullsFirst(Comparator.comparing(dto -> {
            if (dto.getTodayCheckIn() == null) {
                return 0;
            }
            return dto.getTodayCheckIn();
        })));
        return planInfoResDTOList;
    }


    /**
     * 今日打卡情况
     *
     * @return
     */
    private Integer getTodayCheckIn(List<String> timeLists, Boolean todayCheckIn) {
        if (todayCheckIn) {
            return 1;
        }
        if (timeLists != null && timeLists.size() > 0) {
            String today = DateUtil.format(new Date(), "yyyy-MM-dd");
            if (CollectionUtil.contains(timeLists, today)) {
                return 2;
            } else {
                return 3;
            }
        }
        return 3;
    }

}
